
#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""
    @author jay.han
"""
import logging,os
import shutil
from cvirt.common.utils import execute
from cvirt.common import exception


from cvirt.common import config
LOG = logging.getLogger("storage.driver")

conf = config.load_settings()

current_path = os.path.dirname(os.path.abspath(__file__))

class BaseStorage(object):

    def __init__(self,storage):
        self.storage = storage

    def get_storage_path(self):
        return self.storage['mount_point']

    def _ensure_folder(self):
        path = self.get_storage_path()
        if not os.path.exists(path) and not os.path.ismount(path):
            LOG.info('ensure_folder for %s' % path)
            try:
                os.makedirs(path)
            except OSError as e:
                if e.errno != 17: #only file exsists error should pass
                    raise

    def mount(self):
        self._ensure_folder()
        try:
            self._mount()
            self.storage.update(dict(status='running'))
        except exception.InvalidSharedStorage:
            #挂载失败后标记存储为异常
            self.storage.update(dict(status='failed'))
            raise

    def _mount(self):
        raise NotImplemented()

    def umount(self):
        self._umount()
        self.clear_dir()

    def clear_dir(self):
        if os.path.exists(self.get_storage_path()):
            shutil.rmtree(self.get_storage_path())

    def list_storage_info(self):
        pass


class LocalPool(BaseStorage):

    def _mount(self):
        #local do nothing
        pass

    def _umount(self):
        pass

    def list_storage_info(self):

        output = execute('LANG=C','df','--block-size=G',self.get_storage_path(),run_as_root=True)[0]
        l = output.split('\n')[1].split()
        return dict(part=l[0],size=l[1].replace('G',''),used=l[2].replace('G',''),
                    available=l[3].replace('G',''),mountpoint=l[5])

class CifsPool(LocalPool):
    def _mount(self):
        try:
            username = self.storage.username if self.storage.username else ''
            password = self.storage.password if self.storage.password else ''

            output, _ = execute('LANG=C','df',run_as_root=True,check_exit_code=False)
            if self.storage.path+" " not in output:
                execute('mount.cifs','%s' % self.storage.path,self.storage.mount_point,'-o','user=%s,pass=%s' % (username,password),
                run_as_root=True)
            else:
                LOG.debug('storage %s already mounted' % self.storage.path)

            with open('/etc/fstab') as f:
                if self.storage.path+" " not in f.read():
                    with open('/etc/fstab','a') as w:
                        escapepath = self.storage.path.replace(' ','\\040')  #man fstab
                        w.write('%s %s cifs defaults,username=%s,password=%s 0 2\n' %
                                   (escapepath,self.storage.mount_point,username,password))
                else:
                    LOG.debug('storage %s already in /etc/fstab' % self.storage.path)


        except exception.ProcessExecutionError:
            LOG.warn('mount cifs %s failed' % self.storage.path)
            raise exception.InvalidSharedStorage()

    def _umount(self):
        try:
            execute('umount',self.storage.mount_point,run_as_root=True)
            execute('sed','-i','s|.*%s.*||' % self.storage.mount_point,'/etc/fstab',run_as_root=True)
        except exception.ProcessExecutionError as e:

            LOG.warn('umount cifs %s failed' % self.storage.mount_point)
            if "device is busy" in str(e):
                raise exception.storageisbusy()
            else:
                raise



class NetworkFilesystemPool(BaseStorage):

    def _execute(self,action):
        LOG.info(action)
        cmd = '%(cpath)s/scripts/%(type)s/storage.sh -s %(cpath)s/scripts/ -c ' \
              '"server=%(host)s|share=%(path)s|mount_point=%(mountpoint)s" -o %(action)s -t nfs' % dict(
                    cpath=current_path,host=self.storage.host,path=self.storage.path,
                     mountpoint=self.storage.mount_point,type=self.storage.protocol,action=action)

        LOG.info("nfs execute cmd : %s" % cmd)
        _,output,err = os.popen3(cmd)
        if err.read():
            raise exception.InvalidSharedStorage()
        return output,err

    def _mount(self):
        LOG.info("mount nfs path %s:%s to %s" % (self.storage.host,self.storage.path,self.get_storage_path()))
        self._execute("ATTACH")

    def _umount(self):
        self._execute('DETACH')

    def list_storage_info(self):
        output,_ = self._execute('GET_DISKS')
        result = {}
        for item in output.read().split('|'):
            if 'FILESYSTEM' in item:
                result['host'],result['path'] = item.split("=")[-1].split(":")
            if 'SIZE' in item:
                result['size'] = item.split('=')[-1]
            if 'USED' in item:
                result['used'] = item.split('=')[-1]
            if 'AVAILABLE' in item:
                result['available'] = item.split('=')[-1]
            if 'MOUNT' in item:
                result['mountpoint'] = item.split('=')[-1]
        return result


class ISCSIPool(BaseStorage):

    def __init__(self, storage):
        super(ISCSIPool, self).__init__(storage)
        # path = self.storage.path
        # if len(path.split('|'))>2:
        #     self.storage.path = path.split('|')[1]
        # self.storage = storage
        # self.source_path = source_path
        # self.host = host
        # self.protocol = 'iscsi'

    def _execute(self, action):
        username = self.storage.username if self.storage.username else ''
        password = self.storage.password if self.storage.password else ''
        cmd = '%(cpath)s/scripts/%(type)s/storage.sh -s %(cpath)s/scripts/ -c ' \
              '"server=%(host)s|targett=%(target)s|path=%(path)s|mount_point=%(mountpoint)s"'\
              ' -p "username=%(username)s|password=%(password)s" -o %(action)s -t iscsi' % dict(
            cpath=current_path, host=self.storage.host, target=self.storage.target,path=self.storage.path,username=username,password=password,
            mountpoint=self.storage.mount_point, type=self.storage.protocol, action=action)

        LOG.info("iscsi execute cmd : %s" % cmd)
        _,output,err = os.popen3(cmd)
        err_msg = err.read()
        if err_msg and err_msg.index('No active sessions') == -1:
            raise exception.InvalidSharedStorage()
        return output,err

    def mount(self):
        LOG.info("mount iscsi target %s to %s" % (self.storage.target, self.get_storage_path()))
        output,_ = self._execute('ATTACH')
        out = output.read()

        if out.find('Unable') != -1:
            raise exception.InvalidSharedStorage()
        # self._execute("FORMAT")

    def umount(self):
        # self._ensure_folder()
        self._execute('DETACH')

    def list_storage_info(self):
        """
        :return:discovery and return iqn info in the specified node.
        """
        result = {'used':0, 'size':0}
        output,_ = self._execute('GET_DISKS')
        out = output.read().split('\n')
        for o in out:
            if o.find('SUMMARY') != -1:
                result['size'] = float(o.split('=')[-1])
        return result

if __name__ == '__main__':
    # config.setup_logging()
    # ls = LocalPool(dict(name='testlocal',mount_point='/opt/tcloud'))
    # print ls.list_storage_info()
    from cvirt.manager.models import Storage
    storage = Storage.objects.get(pk=5)
    iscsi = ISCSIPool(storage)
    print iscsi.list_storage_info()